package com.luqili.utils.pub.district;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 国内行政区划工具类
 *
 * @author luqili 2016年12月19日
 */
public class DistrictUtils {

    /**
     * 市区
     */
    public static final int LEVEL_PROVINCE = 1;
    /**
     * 市区
     */
    public static final int LEVEL_CITY = 2;
    /**
     * 乡镇
     */
    public static final int LEVEL_DISTRICT = 3;

    private static DistrictUtils instance;
    private List<DistrictNode> districts = new ArrayList<>();

    private DistrictUtils() {
        try (InputStream in = this.getClass().getResourceAsStream("/district.data")) {

            @SuppressWarnings("unchecked")
            List<String> lines = IOUtils.readLines(in, "UTF-8");
            for (String line : lines) {
                if (StringUtils.isBlank(line) || line.startsWith("--")) {
                    // 排除空行,注释
                    continue;
                }
                String[] datas = StringUtils.split(line, ":");
                if (datas.length < 3) {
                    throw new RuntimeException("加载数据异常:" + line);
                }
                Integer level = Integer.parseInt(datas[0]);
                String name = datas[1];
                Integer code = Integer.parseInt(datas[2]);
                Integer[] oldCodes = null;
                if (datas.length > 3 && StringUtils.isNotBlank(datas[3])) {
                    String[] ocs = StringUtils.split(datas[3], ",");
                    oldCodes = new Integer[ocs.length];
                    for (int i = 0; i < ocs.length; i++) {
                        oldCodes[i] = Integer.parseInt(ocs[i]);
                    }
                }
                DistrictNode node = new DistrictNode(level, name, code, oldCodes);
                districts.add(node);
            }
        } catch (Exception e) {
            throw new RuntimeException("加载行政区划数据异常", e);
        }
    }

    /**
     * 获取工具实例
     *
     * @return
     */
    public static DistrictUtils getInstance() {
        if (instance == null) {
            instance = new DistrictUtils();
        }
        return instance;
    }

    public static void main(String[] args) {
        String add1 = DistrictUtils.getInstance().getDistrictFullName(DistrictUtils.getInstance().getDistrictsByAddress("山东省泰安市泰山区金山路"));
        System.out.println(add1);
    }

    /**
     * 根据行政编号获取匹配的行政节点
     *
     * @param code 100000 ~ 999999
     * @return
     */
    public DistrictNode getDistrict(Integer code) {
        if (code == 0) {
            return null;
        }
        if (code < 10) {
            throw new RuntimeException("行政区号异常:" + code);
        } else if (code < 100) {
            code = code * 10000;
        } else if (code < 1000) {
            throw new RuntimeException("行政区号异常:" + code);
        } else if (code < 10000) {
            code = code * 100;
        }
        for (DistrictNode node : districts) {
            if (code.equals(node.getCode())) {
                return node;
            }
        }
        // 匹配历史记录
        for (DistrictNode node : districts) {
            for (Integer oc : node.getCodes()) {
                if (code.equals(oc)) {
                    return node;
                }
            }
        }
        return null;
    }

    /**
     * 查询所在行政区划
     * <li>(371521) 山东省,聊城市,阳谷县
     * <li>(371599) 山东省,聊城市
     *
     * @param code 100000 ~ 999999
     * @return
     */
    public List<DistrictNode> getDistricts(Integer code) {

        List<DistrictNode> ds = new ArrayList<DistrictNode>();
        if (code % 10000 != 0) {
            // 查询所在城市
            Integer pCode = code / 10000 * 10000;
            DistrictNode pNode = getDistrict(pCode);
            if (pNode != null) {
                ds.add(pNode);
            }
        }
        if (code % 100 != 0) {
            // 查询所在城市
            Integer cCode = code / 100 * 100;
            DistrictNode cNode = getDistrict(cCode);
            if (cNode != null) {
                ds.add(cNode);
            }
        }
        DistrictNode node = getDistrict(code);
        if (node != null) {
            ds.add(node);
        }
        return ds;
    }

    /**
     * 根据名称匹配
     * <li>山东=> 山东省
     * <li>山东省 => 山东省
     * <li>山东省聊城 => null
     * <li>聊城=> 聊城市
     * <li>聊城市 => 聊城市
     * <li>聊城市区 => null
     * <li>山 => null
     *
     * @param name 大于1个字符
     * @return
     */
    public DistrictNode getDistrict(String name) {
        return getDistrict(name, null);
    }

    /**
     * 根据名称匹配
     * <li>山东=> 山东省
     * <li>山东省 => 山东省
     * <li>山东省聊城 => null
     * <li>聊城=> 聊城市
     * <li>聊城市 => 聊城市
     * <li>聊城市区 => null
     * <li>山 => null
     *
     * @param name  大于1个字符
     * @param level
     * @return
     */
    public DistrictNode getDistrict(String name, Integer level) {
        if (StringUtils.isBlank(name)) {
            return null;
        }
        if (name.trim().length() < 2) {
            return null;
        }
        for (DistrictNode node : districts) {
            if (level != null && !node.getLevel().equals(level)) {
                continue;
            }
            if (node.getName().startsWith(name)) {
                return node;
            }
        }
        return null;
    }

    /**
     * 获得相关行政区划
     *
     * @param address
     * @return
     */
    public List<DistrictNode> getDistrictsByAddress(String address) {
        if (StringUtils.isBlank(address)) {
            return null;
        }
        String[] suffixs = "省,市,县,区,州,辖,旗,岛,盟,域".split(",");
        String handAdd = address;
        List<DistrictNode> nodes = new ArrayList<DistrictNode>();
        for (String suffix : suffixs) {
            if (handAdd.contains(suffix)) {
                Integer index = handAdd.indexOf(suffix);
                String dName = handAdd.substring(0, index + 1);
                handAdd = handAdd.substring(index + 1);
                if (dName.length() < 2) {
                    // 排除长度
                    continue;
                }
                if (nodes.isEmpty()) {
                    DistrictNode node = getDistrict(dName);
                    if (node != null) {
                        nodes.add(node);
                    }
                } else {
                    DistrictNode pNode = null;
                    DistrictNode cNode = null;
                    DistrictNode dNode = null;
                    for (DistrictNode n : nodes) {
                        if (n.getLevel() == LEVEL_PROVINCE) {
                            pNode = n;
                        } else if (n.getLevel() == LEVEL_CITY) {
                            cNode = n;
                        } else if (n.getLevel() == LEVEL_DISTRICT) {
                            dNode = n;
                        }
                    }
                    if (dNode != null) {
                        // 已经到县,不再分析
                        break;
                    } else if (cNode != null) {
                        // 往下分析时必须在该城市内
                        for (DistrictNode dis : districts) {
                            if (dis.getLevel() == LEVEL_DISTRICT && dis.getCode() / 100 == cNode.getCode() / 100) {
                                if (dis.getName().startsWith(dName)) {
                                    nodes.add(dis);
                                }
                            }
                        }
                    } else if (pNode != null) {
                        // 往下分析时必须在该省内
                        for (DistrictNode dis : districts) {
                            if (dis.getCode() / 10000 == pNode.getCode() / 10000) {
                                if (dis.getName().startsWith(dName)) {
                                    nodes.add(dis);
                                }
                            }
                        }
                    }

                }

            }
        }
        DistrictNode pNode = null;
        DistrictNode cNode = null;
        DistrictNode dNode = null;
        for (DistrictNode n : nodes) {
            if (n.getLevel() == LEVEL_PROVINCE) {
                pNode = n;
            } else if (n.getLevel() == LEVEL_CITY) {
                cNode = n;
            } else if (n.getLevel() == LEVEL_DISTRICT) {
                dNode = n;
            }
        }
        if (cNode == null && dNode != null) {
            cNode = getDistrict(dNode.getCode() / 100 * 100);
            if (cNode != null) {
                nodes.add(cNode);
            }
        }
        if (pNode == null) {
            if (cNode != null) {
                pNode = getDistrict(cNode.getCode() / 10000 * 10000);
            } else if (dNode != null) {
                pNode = getDistrict(dNode.getCode() / 10000 * 10000);
            }
            if (pNode != null) {
                nodes.add(pNode);
            }
        }
        return nodes;
    }

    /**
     * 是否包含该行政区划
     *
     * @param distirct
     * @return
     * @author luqili 2016年12月19日
     */
    public boolean containsDistrict(String distirct) {
        Integer dis = Integer.parseInt(distirct);
        return containsDistrict(dis);
    }

    /**
     * 是否包含该行政区划
     *
     * @param code
     * @return
     * @author luqili 2016年12月19日
     */
    public boolean containsDistrict(Integer code) {
        return getDistrict(code) != null;
    }

    /**
     * 根据行政区划，返回名称，不含有的返回 ""
     *
     * @param district
     * @return
     * @author luqili 2016年12月19日
     */
    public String getDistrictName(Integer district) {
        DistrictNode node = getDistrict(district);
        return node == null ? "" : node.getName();
    }

    /**
     * 获得行政区划全称
     *
     * @param code
     * @return
     * @author luqili 2016年12月19日
     */
    public String getDistrictFullName(Integer code) {
        List<DistrictNode> nodes = getDistricts(code);
        return getDistrictFullName(nodes);
    }

    /**
     * 获得行政区划全称
     *
     * @param nodes
     * @return
     */
    public String getDistrictFullName(List<DistrictNode> nodes) {
        if (nodes == null || nodes.isEmpty()) {
            return "";
        }
        DistrictNode pNode = null;
        DistrictNode cNode = null;
        DistrictNode dNode = null;
        for (DistrictNode n : nodes) {
            if (n.getLevel() == LEVEL_PROVINCE) {
                pNode = n;
            } else if (n.getLevel() == LEVEL_CITY) {
                cNode = n;
            } else if (n.getLevel() == LEVEL_DISTRICT) {
                dNode = n;
            }
        }
        StringBuilder sb = new StringBuilder();
        if (pNode != null) {
            sb.append(pNode.getName());
        }
        if (cNode != null) {
            if (pNode == null || !cNode.getName().equals(pNode.getName())) {
                sb.append(cNode.getName());
            }
        }
        if (dNode != null) {
            sb.append(dNode.getName());
        }
        return sb.toString();
    }

    /**
     * 获得所有的行政区划代码
     *
     * @return
     */
    public Set<Integer> getDistrictCodes() {
        Set<Integer> dis = new HashSet<Integer>();
        for (DistrictNode node : districts) {
            dis.add(node.getCode());
        }
        return dis;
    }

    /**
     * 获得所有的行政区划名称
     *
     * @return
     */
    public List<String> getDistrictNames() {
        List<String> names = new ArrayList<String>();
        for (DistrictNode node : districts) {
            names.add(node.getName());
        }
        return names;
    }

    /**
     * 获得指定级别的全部行政区划信息
     *
     * @param level 为空返回全部
     * @return
     */
    public List<DistrictNode> getAllDistricts(Integer level) {
        List<DistrictNode> nodes = new ArrayList<DistrictNode>();
        for (DistrictNode node : districts) {
            if (level != null && node.getLevel().compareTo(level) == 0) {
                nodes.add(node);
            }
        }
        return nodes;
    }

}
